package com.decent.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.decent.dao.CardMapper;
import com.decent.dao.OrderMapper;
import com.decent.dto.CouponPayDTO;
import com.decent.entity.*;
import com.decent.entity.common.Message;
import com.decent.entity.common.MyException;
import com.decent.dto.ResponseDTO;
import com.decent.entity.common.TestInfoEntity;
import com.decent.enums.ChengQuanResponseEnum;
import com.decent.enums.ExceptionEnum;
import com.decent.enums.MessageEnum;
import com.decent.service.OrderService;
import com.decent.service.ProductService;
import com.decent.util.*;
import com.decent.vo.OrderDetailVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.*;

/**
 * @Author decent
 * @Create 2021/4/8 - 10:54
 * @Description
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private CardMapper cardMapper;

    @Resource
    private ProductService productService;

    @Resource
    private TestInfoEntity entity;

    Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 链接
     */
    private static final String LINK = "LINK";

    /**
     * 链接
     */
    private static final String PICTURE = "PICTURE";

    /**
     * 卡号和密码
     */
    private static final String NUMBER_PASSWORD = "NUMBER_PASSWORD";

    /**
     * 密码
     */
    private static final String PASSWORD = "PASSWORD";

    /**
     * 我的订单
     *
     * @param pageNumber  页码
     * @param pageSize    每页数量
     * @param orderStatus 订单状态 默认：SUCCESS
     * @return OrderDetailVO分页信息
     */
    @Override
    public PageInfo<OrderDetailVO> listUserOrder(Integer pageNumber, Integer pageSize, String orderStatus, Integer uid) {
        return PageHelper.startPage(pageNumber, pageSize).doSelectPageInfo(() -> {
            orderMapper.selectUserOrder(orderStatus, uid);
        });
    }

    /**
     * 立即下单(只是计算获取订单信息)
     *
     * @param productId 产品Id
     * @param count     购买数
     * @return id productName iconUrl count payPrice totalPrice
     */
    @Override
    public Message orderSubmit(Long productId, Integer count, Integer uid) {
        Product product = productService.goodsNoByProductId(productId);
        if (Objects.isNull(product)) {
            return new Message(MessageEnum.NO_PRODUCT);
        }
        // 库存不足
        int stock = HttpUtil.getStock(entity, product.getGoodsNo());
        if (stock < 0) {
            return new Message(MessageEnum.NO_PRODUCT);
        } else if (stock < count) {
            return new Message(MessageEnum.STOCK_NO_ENOUGH);
        }

        // 返回结果
        OrderDetailVO result = new OrderDetailVO();
        result.setId(product.getId());
        result.setProductName(product.getProductName());
        result.setIconUrl(product.getPicUrl());
        result.setCount(count);
        result.setPayPrice(new BigDecimal(product.getSellPrice().intValue() * count));
        result.setTotalPrice(product.getOfficialPrice().intValue() * count + "");
        result.setIntegral(product.getOfficialPrice().intValue() * count);
        return new Message(MessageEnum.GENERAL_REQUEST_SUCCESS, result);
    }

    /**
     * 立即支付
     *
     * @param productId 产品Id
     * @param count     购买数
     * @param uid       用户id
     * @return orderId payPrice
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Message orderPay(Long productId, Integer count, Integer uid) {

        Product product = productService.goodsNoByProductId(productId);
        if (Objects.isNull(product)) {
            return new Message(MessageEnum.NO_PRODUCT);
        }
        // 库存不足
        int stock = HttpUtil.getStock(entity, product.getGoodsNo());
        if (stock < 0) {
            return new Message(MessageEnum.NO_PRODUCT);
        } else if (stock < count) {
            return new Message(MessageEnum.STOCK_NO_ENOUGH);
        }

        // 响应接口，获得data参数转换成List<CouponPay>
        String orderPay = HttpUtil.orderPay(entity, product.getGoodsNo(), count);
        ResponseDTO responseEntity = JSONObject.parseObject(orderPay, ResponseDTO.class);
        if (!ChengQuanResponseEnum.REQUEST_SUCCESS.getCode().equals(responseEntity.getCode())) {
            throw new MyException(ExceptionEnum.ORDER_REQUEST_ERROR);
        }

        List<CouponPayDTO> couponPays = JSONObject.parseArray(responseEntity.getData().toString(), CouponPayDTO.class);
        List<Card> cards = new ArrayList<>(couponPays.size());

        CouponPayDTO firstCouponPay = couponPays.get(0);

        // 从CouponPay获得Order
        Order order = couponPayToOrder(firstCouponPay, product, count, uid);
        int insert = orderMapper.insert(order);
        if (insert < 1) {
            throw new MyException(ExceptionEnum.INSERT_ORDER_ERROR);
        }

        couponPays.forEach(couponPay -> {
            // 解码
            decryptCouponPay(couponPay);
            // 从CouponPay获得Card
            Card card = couponPayToCard(couponPay, productId, order.getId());
            cards.add(card);
        });

        // 更新库存
        Integer integer = productService.updateStockByProductId(productId, count);
        if (integer < 1) {
            throw new MyException(ExceptionEnum.STOCK_UPDATE_ERROR);
        }
        // 数据库添加卡券
        int cardNum = cardMapper.insertCards(cards);
        if (cardNum < count) {
            throw new MyException(ExceptionEnum.INSERT_CARD_ERROR);
        }

        logger.info("订单支付:" + order.toString());

        Map<String, Object> result = new HashMap(3);
        result.put("orderId", order.getId());
        result.put("payPrice", order.getPayPrice());

        return new Message(MessageEnum.GENERAL_REQUEST_SUCCESS, result);
    }

    /**
     * 查看卡券(订单产品详情)
     *
     * @param orderId 订单id
     * @param uid     用户id
     * @return
     */
    @Override
    public List<OrderDetailVO> detailsOrder(Long orderId, Integer uid) {
        return orderMapper.detailsOrder(orderId, uid);
    }


    /**
     * AES解密
     * @param couponPay couponPay
     */
    private void decryptCouponPay(CouponPayDTO couponPay) {
        try {
            switch (couponPay.getGoodsType()) {
                case LINK:
                case PICTURE:
                    couponPay.setGoodsLink(AesUtil.decrypt(couponPay.getGoodsLink(),
                            entity.getAseSecretKey(), entity.getAseOffset()));
                    break;
                case NUMBER_PASSWORD:
                    couponPay.setGoodsNumber(AesUtil.decrypt(couponPay.getGoodsNumber(),
                            entity.getAseSecretKey(), entity.getAseOffset()));
                case PASSWORD:
                    couponPay.setGoodsPassword(AesUtil.decrypt(couponPay.getGoodsPassword(),
                            entity.getAseSecretKey(), entity.getAseOffset()));
                    break;
                default:
                    break;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    private Order couponPayToOrder(CouponPayDTO firstCouponPay, Product product, Integer count, Integer uid) {
        return Order.builder().userOrderNo(firstCouponPay.getUserOrderNo())
                .productId(product.getId()).count(count)
                .payPrice(firstCouponPay.getPrice().multiply(new BigDecimal(3)))
                .orderStatus(firstCouponPay.getState())
                .totalPrice(product.getOfficialPrice().multiply(new BigDecimal(count)) + "")
                .integral(product.getOfficialPrice().multiply(new BigDecimal(count)).intValue())
                .createTime(Instant.ofEpochMilli(firstCouponPay.getCreateTime()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime())
                .buyTime(Instant.ofEpochMilli(firstCouponPay.getCreateTime()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime())
                .uid(uid)
                .build();
    }

    private Card couponPayToCard(CouponPayDTO couponPay, Long productId, Long orderId) {
        return Card.builder().cardNumber(couponPay.getGoodsNumber()).cardPwd(couponPay.getGoodsPassword())
                .cardLink(couponPay.getGoodsLink())
                .cardType(couponPay.getGoodsType())
                .purchaseDate(Instant.ofEpochMilli(couponPay.getCreateTime()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime())
                .effectiveTime(Instant.ofEpochMilli(couponPay.getEffectiveTime()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime())
                .completeTime(Instant.ofEpochMilli(couponPay.getCompleteTime()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime())
                .orderNo(couponPay.getOrderNo())
                .productId(productId).orderId(orderId)
                .build();
    }



}
